#pragma once
#include <iostream>
#include <unordered_map>
#include <vector>
#include <cassert>
#include <sstream>

#include "../comm/Logger.hpp"
#include "../comm/Util.hpp"
#include <mysql/mysql.h>

// mysql version
namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;
    struct Question
    {
        std::string number; // 题目编号
        std::string title;  // 题目标题
        std::string star;   // 题目难度
        std::string header; // 预先设置的代码
        std::string tail;   // 测试用例
        std::string dest;   // 题目描述
        int cpu_limit;      // 时间复杂度
        int mem_limit;      // 空间复杂度
    };

    const std::string mysql_table = "oj_questions";
    const std::string host = "localhost";
    const std::string user = "oj_client";
    const std::string passwd = "123321";
    const std::string db = "oj";
    unsigned int port = 3306;
    const uint64_t cols = 8;

    // 用于和数据进行交互，管理核心的数据和状态
    class Model
    {
    public:
        Model()
        {
        }

        bool QueryMysql(const std::string sql, std::vector<Question> *out)
        {
            // get mysql handle
            MYSQL* mysql = mysql_init(nullptr);
            
            // get connect
            if(nullptr == mysql_real_connect(mysql, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0))
            {
                LOG(LogLevel::FATAL) << "mysql connect err! Please Check!";
                return false;
            }
            
            // LOG(LogLevel::DEBUG) << "mysql user:" << user << " connect success";
            // set character
            mysql_set_character_set(mysql, "utf8");

            // execute mysql
            int n = mysql_query(mysql, sql.c_str());
            if(n != 0)
            {
                // success 
                LOG(LogLevel::WARNING) << sql << " execute error";
                return false;
            }
            // Extraction result
            MYSQL_RES* res = mysql_store_result(mysql);

            // analysis result
            uint64_t rows = mysql_num_rows(res);

            for(int i=0; i<rows; i++)
            {
                // 获取指定一行，其实就是获取char**
                MYSQL_ROW row = mysql_fetch_row(res); // 会帮我们自动++
                if(row == nullptr){
                    LOG(LogLevel::FATAL) << "Not obtained data";
                    return false;
                }
                uint64_t field = mysql_num_fields(res);
                if(field < cols){
                    LOG(LogLevel::FATAL) << "data error(inconsistency)";
                    return false;
                }
                Question q;
                q.number = row[0];
                q.title = row[1];
                q.star = row[2];
                q.dest = row[3];
                q.header = row[4];
                q.tail = row[5];
                q.cpu_limit = std::stoi(row[6]);
                q.mem_limit = std::stoi(row[7]);
                out->push_back(q);
            }
            mysql_free_result(res); // 释放资源，防止内存泄漏
            // close mysql connect
            mysql_close(mysql);
            return true;
        }

        bool GetAllQuestions(std::vector<Question> *out)
        {
            std::string sql = "select * from ";
            sql += mysql_table;
            return QueryMysql(sql, out);
        }

        bool GetOneQuestion(const std::string &number, Question *out)
        {
            bool status = false;
            std::string sql = "select * from ";
            sql += mysql_table;
            sql += " where number = ";
            sql += number;
            std::vector<Question> vq;
            if (QueryMysql(sql, &vq))
            {
                if (vq.size() == 1)
                {
                    *out = vq[0];
                    status = true;
                }
            }

            return status;
        }

        ~Model() {}
    };
}